package com.bqtt.tumor.demo.data_access;

import java.util.List;
import java.util.Map;
import java.util.Set;

import javax.inject.Inject;

import org.hibernate.Query;
import org.hibernate.SessionFactory;
import org.hibernate.classic.Session;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.bqtt.tumor.demo.common.utility.InlineTools;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

public abstract class BasicDAO<EitityT> {

	private SessionFactory sessionFactory;

	private Logger log = LoggerFactory.getLogger(getClass());

	String className;

	public BasicDAO() {
		className = getEntityClassName(0);
	}

	private Session currentSession() {
		return sessionFactory.getCurrentSession();
	}

	public EitityT findById(java.lang.Integer id) {
		try {
			EitityT instance = (EitityT) currentSession().get(className, id);
			return instance;
		} catch (RuntimeException re) {
			throw re;
		}
	}

	public List findByProperty(String propertyName, Object value) {

		log.debug("finding " + className + " instance with property: "
				+ propertyName + ", value: " + value);
		try {
			String stringValue = InlineTools.object2SQLString(value);
			String queryString = "from " + className + " as model where model."
					+ propertyName + "= " + stringValue;
			return currentSession().createQuery(queryString).list();
		} catch (RuntimeException re) {
			log.error("find by property name failed", re);
			throw re;
		}
	}

	public List findAll()
	{
		log.debug("finding all " + className + " instances");
		try {
			String queryString = "from " + className + " as model where 1 = 1";
			return currentSession().createQuery(queryString).list();
		} catch (RuntimeException re) {
			log.error("find all failed", re);
			throw re;
		}
	}
	
	public List fuzzyFindByProperties(Map<String,Object> paramMap)
	{
		Set<String> keys = paramMap.keySet();
		String queryConditions = "";
		for(String item:keys)
		{
			queryConditions = queryConditions+"model."+ item +" " + InlineTools.object2SQLFuzzyMatchString(paramMap.get(item)) +" and ";
		}
		queryConditions +=" 1=1";
		
		log.debug("finding " + className + " instance with multiple properties. Query conditions are: "+queryConditions);
		try {
			
			String stringValue = "";
			String queryString = "from " + className + " as model where " + queryConditions;
			
			
			return currentSession().createQuery(queryString).list();
		} catch (RuntimeException re) {
			log.error("find by property name failed", re);
			throw re;
		}
	}
	
	public List fuzzyFindByProperties(Map<String,Object> paramMap,int pageSize,int pageNumber)
	{
		if(pageNumber<=0)
		{
			log.error("[SQL Exception] pageNumber不能小于1，（从1开始）。");
			return null;
		}
		Set<String> keys = paramMap.keySet();
		String queryConditions = "";
		for(String item:keys)
		{
			queryConditions = queryConditions+"model."+ item +" " + InlineTools.object2SQLFuzzyMatchString(paramMap.get(item)) +" and ";
		}
		//queryConditions +=" 1=1 limit "+(pageNumber-1)*pageSize+", "+pageSize;
		queryConditions += " 1=1";
		log.debug("finding " + className + " instance with multiple properties. Query conditions are: "+queryConditions);
		try {
			
			String stringValue = "";
			String queryString = "from " + className + " as model where " + queryConditions +" order by 1 desc";
			
			Query query = currentSession().createQuery(queryString);
			query.setFirstResult((pageNumber-1)*pageSize);
			query.setMaxResults(pageSize);
			
			
			return query.list();
		} catch (RuntimeException re) {
			log.error("find by property name failed", re);
			throw re;
		}
	}
	
	public List findByProperties(Map<String,Object> paramMap) {

		
		Set<String> keys = paramMap.keySet();
		String queryConditions = "";
		for(String item:keys)
		{
			queryConditions = queryConditions+"model."+ item +" = " + InlineTools.object2SQLString(paramMap.get(item)) +" and ";
		}
		queryConditions +=" 1=1";
		
		log.debug("finding " + className + " instance with multiple properties. Query conditions are: "+queryConditions);
		try {
			
			String stringValue = "";
			String queryString = "from " + className + " as model where " + queryConditions;
			
			
			return currentSession().createQuery(queryString).list();
		} catch (RuntimeException re) {
			log.error("find by property name failed", re);
			throw re;
		}
	}
	
	
	public void save(EitityT transientInstance) {
		log.debug("saving " + getEntityClassName(0) + " instance");
		try {
			currentSession().save(transientInstance);
			log.debug("save successful");
		} catch (RuntimeException re) {
			log.error("save failed", re);
			throw re;
		}
	}
	
	public void update(EitityT transientInstance) {
		log.debug("updating " + getEntityClassName(0) + " instance");
		try {
			currentSession().update(transientInstance);
			log.debug("update successful");
		} catch (RuntimeException re) {
			log.error("update failed", re);
			throw re;
		}
	}

	public boolean delete(EitityT transientInstance)
	{
		log.debug("deleting " + getEntityClassName(0) + " instance");
		try {
			currentSession().delete(transientInstance);
			log.debug("update successful");
			return true;
		} catch (RuntimeException re) {
			log.error("update failed", re);
			return false;
		}
	}
	public SessionFactory getSessionFactory() {
		return sessionFactory;
	}

	@Inject
	public void setSessionFactory(SessionFactory sessionFactory) {
		this.sessionFactory = sessionFactory;
	}

	public String getEntityClassName(int index) {
		return getTClass(index).getName();
	}

	public Class getTClass(int index) {

		Type genType = getClass().getGenericSuperclass();

		if (!(genType instanceof ParameterizedType)) {
			return Object.class;
		}

		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

		if (index >= params.length || index < 0) {
			throw new RuntimeException("Index out of bounds");
		}

		if (!(params[index] instanceof Class)) {
			return Object.class;
		}
		return (Class) params[index];
	}
	
	
	
	
	
}
